Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Civl] Fix to heuristic for variable elimination in transition relation computation #677

Merged
merged 13 commits into from
Jan 14, 2023

Conversation

shazqadeer
Copy link
Contributor

@shazqadeer shazqadeer commented Jan 11, 2023

The investigation behind this PR started when I attempted to eliminate the duplication between the abstract and concrete actions used in the IS proof of NBuyer. I wanted to simply call the concrete atomic action from the abstract one right after the extra asserts had been added. I discovered that the refactored code did not verify due to proof flakiness. The changes to the sample were my efforts (not all of which may have been necessary) to reduce the flakiness while still achieving no duplication of code. In the process, I also attempted to generalize the heuristic for variable elimination in computation of transition relations. The revised (more powerful) heuristic is needed for the revised version of NBuyer.bpl otherwise the cooperation check for MiddleBuyer' does not verify.

The change to transition relation computation is in the second attempt to eliminate temporaries. Before this PR, the second attempt used as defined only the initial incarnations of locals. The PR changes this logic to allow as defined any incarnation that does not have a definition among assignments. Thus, all incarnations generated by havocs are also considered as defined.

While working on this PR, I discovered that the computation of transition relation of atomic actions also uses patterns. The triggers for these patterns are injected in the body of atomic actions. The instantiation induced by these triggers is more precise than what is achievable today via pools. Furthermore, the triggers appear to be needed for the verification of commutativity checks. This PR also modifies the trigger generation. Before this PR, triggers were being generated only for the initial incarnation of local variables. This PR adds trigger generation for incarnations created due to havoc commands as well. Live variable analysis is done over the body of atomic actions to avoid adding triggers for incarnations that are not live. This optimization appears to be important for the commutativity check between A_Propose and A_Propose'. This check quickly starts to become expensive with more instantiations, either due to triggers or due to pools. This explosive growth in running time is a ticking time bomb in the scalability of Civl.

The overall effect of this PR is to eliminate the duplication between concrete and abstract actions across our entire set of benchmarks.

@shazqadeer shazqadeer requested a review from bkragl January 11, 2023 21:42
Comment on lines 351 to 358
if (trc.allLocVars.Count > 0)
{
for (int i = 1; i <= trc.allLocVars.Select(v => varCopies[v].Count).Max(); i++)
{
TryElimination(trc.allLocVars.SelectMany(v =>
varCopies[v].GetRange(0, i <= varCopies[v].Count ? i : varCopies[v].Count)));
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Took me a minute to understand. Maybe a comment explaining that we are eliminating with increasing sets of copies (copies 0, copies 0+1, ...) would be helpful. Two minor suggestions:

  1. Extract trc.allLocVars.Select(v => varCopies[v].Count).Max() to a variable.
  2. Replace i <= varCopies[v].Count ? i : varCopies[v].Count with Math.min(i, varCopies[v].Count).

Is there an intuitive reason why exactly this heuristic? I get that the initial copies and final copies belong together, since they form the pre and post state. But is there something that connects the i-th copies?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bkragl : Thanks so much for attempting to understand this modification. After my first attempt, I realized that my intention was to do something else. I have pushed a revision, this time including some comments. Let me know what you think.

Comment on lines 208 to +209
assert Init(pids, ReqCH, QuoteCH, RemCH, DecCH, contribution);
QuoteCH := (lambda i:int :: (lambda q:int :: if buyerID(i) && q == price then 1 else 0));
assume {:add_to_pool "contribution", contribution} true;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it make sense to attach the add_to_pool attribute to the assertion or better keep it separate? Wondering if there is any convention.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have recently realized that putting :add_to_pool annotations on asserts in the body of atomic actions is not being handled correctly since I added the HoistAsserts code. This code is not propagating the attributes on the asserts as it hoists them.

I am unsure what to do. I am thinking about restricting the scope of add_to_pool even further in the documentation allowing them to be used only on assume commands.

@@ -1,2 +1,2 @@

Boogie program verifier finished with 130 verified, 0 errors
Boogie program verifier finished with 132 verified, 0 errors
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are there 2 extra VCs now?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know. I was mystified too.

@@ -47,13 +47,12 @@ function max(CH:[val]int) : val;
function card(CH:[val]int) : int;

axiom card(MultisetEmpty) == 0;
axiom (forall v:val :: card(MultisetSingleton(v)) == 1);
axiom (forall CH:[val]int, v:val :: card(MultisetPlus(CH, MultisetSingleton(v))) == card(CH) + 1);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On my machine this axiom can be removed too.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

axiom (forall CH:[val]int, v:val :: card(MultisetPlus(CH, MultisetSingleton(v))) == card(CH) + 1);
axiom (forall CH:[val]int, v:val :: {CH[v := CH[v] + 1]} card(CH[v := CH[v] + 1]) == card(CH) + 1);
axiom (forall m:[val]int, m':[val]int :: {card(m), card(m')} MultisetSubsetEq(m, m') && card(m) == card(m') ==> m == m');
axiom (forall CH:[val]int, v:val, x:int :: card(CH[v := x]) == card(CH) + x - CH[v]);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!


axiom (forall v:val :: max(MultisetSingleton(v)) == v);
axiom (forall CH:[val]int, v:val :: { CH[v := CH[v] + 1] } max(CH[v := CH[v] + 1]) == (if v > max(CH) then v else max(CH)));
axiom (forall CH:[val]int, v:val, x:int :: max(CH[v := x]) == (if v > max(CH) && x > 0 then v else max(CH)));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: make x > 0 the lhs of an implication

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@bkragl bkragl self-requested a review January 12, 2023 21:31
bkragl
bkragl previously approved these changes Jan 12, 2023
shazqadeer and others added 3 commits January 12, 2023 19:50
fix to heuristic for variable elimination
@shazqadeer shazqadeer enabled auto-merge (squash) January 14, 2023 18:14
@shazqadeer shazqadeer disabled auto-merge January 14, 2023 18:14
@shazqadeer shazqadeer merged commit 5c69809 into master Jan 14, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants